﻿namespace WLFramework.IoC
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// Ioc依赖注入容器
    /// </summary>
    public class IocContainer : IIocContainer
    {
        private static readonly string DefaultLabel = Guid.NewGuid().ToString();

        private readonly IDictionary<string, IList<IIocRegisterService>> _containers =
            new Dictionary<string, IList<IIocRegisterService>>();

        private readonly object _mutex = new object();

        public IocContainer()
        {
        }

        #region 接口
        /// <summary>
        /// 注册依赖对象的类型的创建函数，标记名称
        /// </summary>
        /// <typeparam name="T">要实现的类型</typeparam>
        /// <param name="creation">需要实现的类型的创建函数</param>
        /// <param name="label">标记名称</param>
        public void Register<T>(Func<IIocContainer, T> creation, string label = "")
        {
            Shield.AssertNotNull(ref creation, "creation");

            label = string.IsNullOrEmpty(label) ? DefaultLabel : label;

            this.CheckContainer(label);

            lock (this._mutex)
            {
                this.CheckExists(label, typeof(T));

                var register = new IocRegisterService<T>(creation);
                this._containers[label].Add(register);
            }
        }

        /// <summary>
        /// 获取类型实现后的对象， 默认单例模式
        /// </summary>
        /// <typeparam name="T">需要实现的类型</typeparam>
        /// <param name="label">标记名称</param>
        /// <returns>实现后的对象</returns>
        public T Resolve<T>(string label = "")
        {
            label = this.GetLabel(label);
            return Resolve<T>(true, label);
        }

        /// <summary>
        /// 获取类型实现后的对象
        /// </summary>
        /// <typeparam name="T">需要实现的类型</typeparam>
        /// <param name="createNew">是否创建新的对象</param>
        /// <param name="label">标记名称</param>
        /// <returns>实现后的对象</returns>
        public T Resolve<T>(bool createNew, string label = "")
        {
            label = this.GetLabel(label);

            this.CheckContainer(label);
            this.CheckExists(label, typeof(T));

            lock (this._mutex)
            {
                var register = this._containers[label]
                    .FirstOrDefault(ioc => ioc.Type == typeof(T).FullName)
                    as IocRegisterService<T>;

                if (register == null)
                {
                    throw new InvalidOperationException("Resolve Failed!");
                }

                return register.GetTypedInstance(this, createNew);
            }
        }

        /// <summary>
        /// 检查容器是否包含指定的类型实现
        /// </summary>
        /// <typeparam name="T">需要实现的类型</typeparam>
        /// <param name="label">标记名称</param>
        /// <returns>true or false</returns>
        public bool CanResolve<T>(string label = "")
        {
            label = this.GetLabel(label);
            return this.Exists(label, typeof(T));
        }

        /// <summary>
        /// 获取类型实现后的对象，默认单例模式
        /// </summary>
        /// <typeparam name="T">需要实现的类型</typeparam>
        /// <param name="instance">输出实现后的对象</param>
        /// <param name="label">标记名称</param>
        /// <returns>执行结果(true or false)</returns>
        public bool TryResolve<T>(out T instance, string label = "")
        {
            label = this.GetLabel(label);
            return this.TryResolve(out instance, true, label);
        }

        /// <summary>
        /// 获取类型实现后的对象
        /// </summary>
        /// <typeparam name="T">需要实现的类型</typeparam>
        /// <param name="instance">输出实现后的对象</param>
        /// <param name="createNew">是否创建新的对象</param>
        /// <param name="label">标记名称</param>
        /// <returns>执行结果(true or false)</returns>
        public bool TryResolve<T>(out T instance, bool createNew, string label = "")
        {
            label = this.GetLabel(label);

            if (this.Exists(label, typeof(T)))
            {
                try
                {
                    instance = this.Resolve<T>(createNew, label);
                    return true;
                }
                catch
                {
                }
            }

            instance = default(T);
            return false;
        }

        /// <summary>
        /// 取消注册的依赖对象类型
        /// </summary>
        /// <typeparam name="T">需要取消的类型</typeparam>
        /// <param name="label">标记名称</param>
        /// <returns>执行结果(true or false)</returns>
        public bool Unregister<T>(string label = "")
        {
            label = this.GetLabel(label);
            var type = typeof(T);

            if (!this.Exists(label, type))
            {
                return false;
            }

            lock (this._mutex)
            {
                if (!this.Exists(label, typeof(T)))
                {
                    return false;
                }

                var list = this._containers[label];
                var register = list.First(c => c.Type == type.FullName);
                list.Remove(register);
                return true;
            }
        }

        /// <summary>
        /// 销毁已经创建的类型的实例
        /// </summary>
        /// <typeparam name="T">需要销毁的类型</typeparam>
        /// <param name="label">标记名称</param>
        /// <returns>执行结果(true or false)</returns>
        public bool Destroy<T>(string label = "")
        {
            label = this.GetLabel(label);
            var type = typeof(T);

            if (!this.Exists(label, type))
            {
                return false;
            }

            lock (this._mutex)
            {
                if (!this.Exists(label, typeof(T)))
                {
                    return false;
                }

                var list = this._containers[label];
                var register = list.First(c => c.Type == type.FullName);
                return register != null && register.DestroyInstance();
            }
        }
        #endregion

        private void CheckContainer(string label)
        {
            Shield.AssertNotNull(ref label, "label");

            if (this._containers.ContainsKey(label))
            {
                return;
            }

            lock (this._mutex)
            {
                if (this._containers.ContainsKey(label))
                {
                    return;
                }

                var list = new List<IIocRegisterService>();
                this._containers.Add(label, list);
            }
        }

        private bool Exists(string label, Type type)
        {
            Shield.AssertNotNull(ref label, "label");
            Shield.AssertNotNull(ref type, "t");

            if (!this._containers.ContainsKey(label))
            {
                return false;
            }

            var fullname = type.FullName;
            lock (this._mutex)
            {
                return this._containers[label].Any(ioc => ioc.Type.Equals(fullname));
            }
        }

        private void CheckExists(string label, Type type)
        {
            if (this.Exists(label, type))
            {
                throw new ArgumentException(
                    string.Format("无法注册类型{0}.", type.FullName));
            }
        }        

        private string GetLabel(string label)
        {
            return string.IsNullOrEmpty(label) ? DefaultLabel : label;
        }
    }
}
